//run mpi solver
//$Id: run_mpi.h 175 2009-09-12 17:34:23Z Oleg.Bulychov $
#pragma once
#ifndef RUN_MPI_H
#define RUN_MPI_H

#include "src/heo/include/ini_file.h"
#include "src/heo/include/fast_stream.h"
#include "src/heo/include/stream_visitor.h"
#include "src/heo/include/transmit_string.h"
#include "src/heo/include/easy_mpi.h"
#include "src/heo/include/config.h"

template<class T>
struct Run_MPI
{
    typedef T                           TSolver;
    typedef typename TSolver::TProblem  TProblem;
    typedef typename TSolver::TSolution TSolution;
    typedef typename TSolver::TConfig   TConfig;

    int retval;

    int run(int argc, char* argv[], char const* szName, int& rank)
    {
        using namespace std;

        setlocale(LC_ALL, "C");//:decimal point must be '.'

        mpi::implementation impl(argc, argv);
        mpi::communicator comm;
        rank  = comm.rank();
        int np = comm.size();
        cout << "rank " << rank << " from " << np << lf;

        TConfig cfg;
        TProblem problem;
        {
            if (0 == rank)
            {
                if (argc != 2)
                {
                    cout << "usage: " << szName << " file.ini" << endl;
                    return -1;
                }

                ini::in ini(argv[1]);
                ini.load(cfg, szName);
                cout << "[" << szName << "]" << lf;
                meta::ostream_visitor kcout(cout);
                kcout << cfg;
                cout << endl;
                if (ini.load_Error())
                    ini::out(argv[1]).save(cfg, szName);
            }
            mpi::bcast(0, comm) >> cfg;

            uniform_random::randomize(1, cfg.rand_seed_ + rank);

            vector<char> buffer;
            {
                ifstream in(cfg.input_file_.c_str());
                if (!in)
                {
                    cout << "ERROR: '" << cfg.input_file_ << "' not found" << endl;
                    return -1;
                }
                in.seekg(0, ios::end);
                streamsize length = in.tellg();
                in.seekg(0, ios::beg);
                buffer.resize(length);
                if (length <= 0)
                {
                    cout << "ERROR: '" << cfg.input_file_ << "' is empty" << endl;
                    return 0;
                }
                in.read(&buffer[0], length);
            }
            fast_istream iss(&buffer[0], buffer.size());//:not copied!
            if (!problem.read(iss))
            {
                cout << "ERROR: '" << cfg.input_file_ << "' corrupted" << endl;
                return -1;
            }
        }

        TSolution sol;
        sol.init(problem, cfg);
        sol.generate_Trivial();

        comm.barrier();

        double start_time = impl.time();
        TSolver::solve(problem, sol, cfg, comm);
        double end_time = impl.time();

        if (0 == rank)
        {
            cout << "time = " << end_time - start_time << " s" << lf
                << "solution:" << lf;
            sol.print(cout, problem, cfg);
        }
        return 0;
    }

    Run_MPI(int argc, char* argv[], char const* szName)
    {
        int rank;
        retval = run(argc, argv, szName, rank);
#if defined(_MSC_VER)
        if (0 == rank)
        {
            extern void If_Debug_Press_Enter();
            If_Debug_Press_Enter();
        }
#endif
    }
};

#endif
//EOF!
